#pragma once
#include <pthread.h>
#include <queue>
namespace Singleton
{
    template <class T>
    class PthreadPool
    {
        static int _default_num;

    private:
        std::queue<T> _ring_queue;
        int _num;
        static PthreadPool *ins;
        pthread_mutex_t _mtx;
        pthread_cond_t _cond;

        static void *processing(void *argv)
        {
            PthreadPool *tp = (PthreadPool *)argv;
            // 线程分离
            pthread_detach(pthread_self());
            // 处理过程
            while (true)
            {
                tp->Lock();
                while (tp->Empty())
                {
                    tp->Wait();
                }
                // 队列里一定有任务
                T data = tp->_ring_queue.front();
                tp->_ring_queue.pop();
                tp->Unlock();
                data.run();
            }
        }

        PthreadPool(int num = _default_num) : _num(num)
        {
            pthread_mutex_init(&_mtx, nullptr);
            pthread_cond_init(&_cond, nullptr);
        }
        PthreadPool(PthreadPool &p)
        {
        }
        PthreadPool &operator=(PthreadPool &p)
        {
        }

    private:
        bool Empty()
        {
            return _ring_queue.empty();
        }
        void Lock()
        {
            pthread_mutex_lock(&_mtx);
        }
        void Unlock()
        {
            pthread_mutex_unlock(&_mtx);
        }
        void Wait()
        {
            pthread_cond_wait(&_cond, &_mtx);
        }
        void Awaken()
        {
            pthread_cond_signal(&_cond);
        }

    public:
        ~PthreadPool()
        {
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_cond);
        }
        // 单例模式 -- 懒汉模型
        static PthreadPool *GetInstance()
        {
            static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
            if (ins == nullptr)
            {
                pthread_mutex_lock(&mtx);
                if (ins == nullptr)
                {
                    ins = new PthreadPool();
                    ins->InitPthreadPool();
                }
                pthread_mutex_unlock(&mtx);
            }

            return ins;
        }
        void InitPthreadPool()
        {
            pthread_t tmp;
            for (int i = 0; i < _num; i++)
            {
                pthread_create(&tmp, nullptr, processing, (void *)this);
            }
        }
        void Push(const T &data)
        {
            Lock();
            _ring_queue.push(data);
            Awaken();
            Unlock();
        }
    };
    template <class T>
    int PthreadPool<T>::_default_num = 5;
    template <class T>
    PthreadPool<T> *PthreadPool<T>::ins = nullptr;

}